Java反射递归比较两个对象(对象中包括对象、List等)里面的不同字段 您所在的位置:网站首页 java 比较对象相同 工具类 Java反射递归比较两个对象(对象中包括对象、List等)里面的不同字段

Java反射递归比较两个对象(对象中包括对象、List等)里面的不同字段

2023-09-03 10:24| 来源: 网络整理| 查看: 265

前言

很多时候,我们需要对两个对象做diff,如果字段一多,比较起来相当的麻烦,利用反射,可以快速的实现一些diff比较,尽量性能不好,这是空间换时间的一些做法。

正文

核心实现如下:

/** * modify field diff util * @author Cao Yong * @date 2021-05-28 9:48:12 */ public class ModifyFieldsDiffUtil { /** * get modify field diffs * @param before before modify DTO * @param after after modify DTO * @param diffs diff list * @param customerClass customer class, need adding all customer diff object * @param class type that diff */ public static void diff(T before, T after, List diffs, Class... customerClass) { //can not be null for all if (before == null && after == null) { return; } //get all fields for none null T allFieldsObj = before == null ? after : before; List finalFields = getClassAllFields(allFieldsObj); //iterator field for (Field declaredField : finalFields) { getDiffInfo(before, after, diffs, declaredField, customerClass); } } /** * get class fields and supper class fields * @param obj object * @return all fields */ private static List getClassAllFields(Object obj) { Field[] superFields = null; Class superclass = obj.getClass().getSuperclass(); //get supper declared fields if (superclass != null) { superFields = superclass.getDeclaredFields(); } //get declared fields Field[] fields = obj.getClass().getDeclaredFields(); //all fields Field[] finalFields; if (superFields != null && superFields.length > 0) { finalFields = new Field[superFields.length + fields.length]; //copy all super field System.arraycopy(superFields, 0, finalFields, 0, superFields.length); //copy all self field System.arraycopy(fields, 0, finalFields, superFields.length, fields.length); } else { finalFields = fields; } return Arrays.stream(finalFields).filter(field -> field.isAnnotationPresent(DiffField.class)).collect(Collectors.toList()); } /** * get diff info * @param before diff before object * @param after diff after object * @param diffs diffs ArrayList * @param declaredField declared field * @param customerClass customer class, need adding all customer diff object */ private static void getDiffInfo(T before, T after, List diffs, Field declaredField, Class... customerClass) { final String uId = "serialVersionUID"; //ignore serialVersionUID if (uId.equals(declaredField.getName())) { return; } Object beforeInvoke = null; Object afterInvoke = null; if (before != null) { try { //get diff before object by invoke beforeInvoke = new PropertyDescriptor(declaredField.getName(), before.getClass()).getReadMethod().invoke(before); } catch (Exception ignored) { } } if (after != null) { try { //get diff after object by invoke afterInvoke = new PropertyDescriptor(declaredField.getName(), after.getClass()).getReadMethod().invoke(after); } catch (Exception ignored) { } } //adding diffs addingDiff(diffs, declaredField, beforeInvoke, afterInvoke, customerClass); if (beforeInvoke != null && afterInvoke != null) { if (beforeInvoke instanceof ArrayList) { List beforeList = (ArrayList) beforeInvoke; List afterList = (ArrayList) afterInvoke; //break when size not equals if (afterList.size() != beforeList.size()) { return; } int index = 0; for (Object beforeObj : beforeList) { //avoid recursive reference if (beforeObj.getClass() == before.getClass()) { throw new RuntimeException("Can not recursive depend"); } //recursive call diff(beforeObj, afterList.get(index), diffs, customerClass); index++; } } } } /** * adding diffs * @param diffs diffs ArrayList * @param declaredField declared field * @param beforeInvoke before invoke value * @param afterInvoke after invoke value * @param customerClass customer class, need adding all customer diff object */ private static void addingDiff(List diffs, Field declaredField, T beforeInvoke, T afterInvoke, Class... customerClass) { //get field annotation DiffField annotation = declaredField.getAnnotation(DiffField.class); //adding string diff if (String.class.getName().equals(declaredField.getType().getName())) { String beforeField = beforeInvoke == null ? "" : (String) beforeInvoke; String afterField = afterInvoke == null ? "" : (String) afterInvoke; if (!beforeField.equals(afterField)) { DiffContent diff = new DiffContent(); diff.setModifyField(annotation == null ? declaredField.getName() : annotation.value()); diff.setModifyField(declaredField.getName()); diff.setBeforeModification(beforeField); diff.setAfterModification(afterField); diffs.add(diff); } } //adding integer diff if (Integer.class.getName().equals(declaredField.getType().getName())) { Integer beforeField = beforeInvoke == null ? 0 : (Integer) beforeInvoke; Integer afterField = afterInvoke == null ? 0 : (Integer) afterInvoke; if (!beforeField.equals(afterField)) { DiffContent diff = new DiffContent(); diff.setModifyField(annotation == null ? declaredField.getName() : annotation.value()); diff.setBeforeModification(String.valueOf(beforeInvoke)); diff.setAfterModification(String.valueOf(afterInvoke)); diffs.add(diff); } } //adding long diff if (Long.class.getName().equals(declaredField.getType().getName())) { Long beforeField = Objects.isNull(beforeInvoke) ? 0 : (Long) beforeInvoke; Long afterField = Objects.isNull(afterInvoke) ? 0 : (Long) afterInvoke; if (!Objects.equals(beforeField, afterField)) { DiffContent diff = new DiffContent(); diff.setModifyField(annotation == null ? declaredField.getName() : annotation.value()); diff.setBeforeModification(String.valueOf(beforeInvoke)); diff.setAfterModification(String.valueOf(afterInvoke)); diffs.add(diff); } } //adding customer class diff if (customerClass != null && customerClass.length > 0) { List customerClassNames = Arrays.stream(customerClass).map(Class::getName).collect(Collectors.toList()); if (customerClassNames.stream().anyMatch(declaredField.getType().getName()::equals)) { //recursive call diff(beforeInvoke, afterInvoke, diffs, customerClass); } } } }

定义diff返回对象

/** * * @author Cao Yong * @date 2021-05-28日 9:52:23 */ @Data public class DiffContent implements Serializable { private static final long serialVersionUID = 646098769625590576L; private String modifyField; private String beforeModification; private String afterModification; }

还可以通过自定义注解来标识字段

/** * * @author Cao Yong * @date 2020-05-28 21:05:23 */ @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DiffField { /** * parent value * @return parent value */ String parentValue() default ""; /** * value * @return value */ String value() default ""; }

注解使用示例:

/** * 主键ID */ @DiffField(parentValue = "资料详情", value = "主键id") private Long id;

测试代码示例:

/** * * @author Cao Yong * @date 2021-05-28日 13:33:23 */ public class DiffMainTest { public static void main(String[] args) throws Exception { DetailDto detail1 = new DetailDto() detail1.setName("test name1"); DetailDto detail2 = new DetailDto() detail2.setName("test name2"); List diffs = new ArrayList(); //RecordDto是对象中自己定义的对象 ModifyFieldsDiffUtil.diff(detail1, detail2, diffs, RecordDto.class); System.out.println("diffs:{}===============" + diffs); } }


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有